import { DeleteOutlined, PlusOutlined } from '@ant-design/icons';
import { useCreation, useMemoizedFn } from 'ahooks';
import { Button, Segmented, Switch } from 'antd';
import React, { useCallback, useMemo, useRef, useState } from 'react';
import { NodeProps } from 'reactflow';
import { useContextSelector } from 'use-context-selector';

import NumberInput from '@/components/inputs/NumberInput';
import PromptEditor from '@/components/Textarea/PromptEditor';
import { t } from '@/locales/i18n';
import { AppContext } from '@/pages/app/detail/context';
import {
  FlowNodeInputMap,
  FlowNodeInputTypeEnum,
  NodeInputKeyEnum,
  WorkflowIOValueTypeEnum,
} from '@/types/workflow/constant';
import { ReferenceValueProps } from '@/types/workflow/io';
import { FlowNodeItemType } from '@/types/workflow/node';
import { TUpdateListItem } from '@/types/workflow/template/system/variableUpdate/type';
import { isReferenceValue } from '@/types/workflow/utils';
import { getRefData } from '@/utils/workflow/utils';

import { WorkflowContext } from '../../../context';
import { getEditorVariables } from '../../../utils';
import NodeCard from '../render/NodeCard';
import { ReferSelector, useReference } from '../render/RenderInput/templates/Reference';

const NodeVariableUpdate = ({ data, selected }: NodeProps<FlowNodeItemType>) => {
  const { inputs = [], nodeId } = data;

  const onChangeNode = useContextSelector(WorkflowContext, (v) => v.onChangeNode);
  const nodeList = useContextSelector(WorkflowContext, (v) => v.nodeList);
  const appDetail = useContextSelector(AppContext, (v) => v.appDetail);
  const edges = useContextSelector(WorkflowContext, (v) => v.edges);

  const menuList = useRef([
    {
      renderType: FlowNodeInputTypeEnum.input,
      icon: FlowNodeInputMap[FlowNodeInputTypeEnum.input].icon,
      label: t('core.workflow.inputType.Manual input'),
    },
    {
      renderType: FlowNodeInputTypeEnum.reference,
      icon: FlowNodeInputMap[FlowNodeInputTypeEnum.reference].icon,
      label: t('core.workflow.inputType.Reference'),
    },
  ]);

  const variables = useCreation(() => {
    return getEditorVariables({
      nodeId,
      nodeList,
      edges,
      appDetail,
      t,
    });
  }, [nodeId, nodeList, edges, appDetail, t]);

  const updateList = useMemo(
    () =>
      (inputs.find((input) => input.key === NodeInputKeyEnum.updateList)
        ?.value as TUpdateListItem[]) || [],
    [inputs],
  );

  const onUpdateList = useCallback(
    (value: TUpdateListItem[]) => {
      const updateListInput = inputs.find((input) => input.key === NodeInputKeyEnum.updateList);
      if (!updateListInput) return;

      onChangeNode({
        nodeId,
        type: 'updateInput',
        key: NodeInputKeyEnum.updateList,
        value: {
          ...updateListInput,
          value,
        },
      });
    },
    [inputs, nodeId, onChangeNode],
  );

  const ValueRender = useMemoizedFn(
    ({ updateItem, index }: { updateItem: TUpdateListItem; index: number }) => {
      const { valueType } = getRefData({
        variable: updateItem.variable,
        nodeList,
        chatConfig: appDetail.chatConfig,
      });
      const renderTypeData = menuList.current.find(
        (item) => item.renderType === updateItem.renderType,
      );

      const nodeIds = nodeList.map((node) => node.nodeId);
      const handleUpdate = (newValue: ReferenceValueProps | string) => {
        if (isReferenceValue(newValue, nodeIds)) {
          onUpdateList(
            updateList.map((update, i) =>
              i === index ? { ...update, value: newValue as ReferenceValueProps } : update,
            ),
          );
        } else {
          onUpdateList(
            updateList.map((update, i) =>
              i === index ? { ...update, value: ['', newValue as string] } : update,
            ),
          );
        }
      };

      const [hover, setHover] = useState(false);

      return (
        <div
          key={index}
          className={`flex items-start rounded-xl p-3 transition-colors duration-200 ${
            hover ? 'bg-@error-color-light' : 'bg-fill-2'
          }`}
        >
          <div className="flex-1">
            <div className="nodrag flex w-full items-center">
              <div className="text-rightflex w-[50px]">{t('core.workflow.variable')} : </div>
              <div className="flex-1">
                <Reference
                  nodeId={nodeId}
                  variable={updateItem.variable}
                  onSelect={(value) => {
                    onUpdateList(
                      updateList.map((update, i) => {
                        if (i === index) {
                          return {
                            ...update,
                            value: ['', ''],
                            valueType,
                            variable: value,
                          };
                        }
                        return update;
                      }),
                    );
                  }}
                />
              </div>
            </div>
            <div className="nodrag mt-2 flex w-full items-start">
              <div className="flex w-[50px] text-right">{t('core.workflow.value')}:</div>
              <div className="flex w-full flex-1 flex-col gap-2">
                <div className="">
                  <Segmented
                    className="workflow-segmented"
                    options={[
                      {
                        label: t('core.workflow.inputType.Manual input'),
                        value: FlowNodeInputTypeEnum.input,
                      },
                      {
                        label: t('core.workflow.inputType.Reference'),
                        value: FlowNodeInputTypeEnum.reference,
                      },
                    ]}
                    value={renderTypeData?.renderType}
                    onChange={(value) => {
                      // onChange(value);
                      onUpdateList(
                        updateList.map((update, i) => {
                          if (i === index) {
                            return {
                              ...update,
                              value: ['', ''],
                              renderType:
                                updateItem.renderType === FlowNodeInputTypeEnum.input
                                  ? FlowNodeInputTypeEnum.reference
                                  : FlowNodeInputTypeEnum.input,
                            };
                          }
                          return update;
                        }),
                      );
                    }}
                  />
                </div>
                {/* Render input components */}
                {(() => {
                  if (updateItem.renderType === FlowNodeInputTypeEnum.reference) {
                    return (
                      <Reference
                        nodeId={nodeId}
                        variable={updateItem.value}
                        valueType={valueType}
                        onSelect={handleUpdate}
                      />
                    );
                  }
                  if (valueType === WorkflowIOValueTypeEnum.string) {
                    return (
                      <div className="w-[300px]">
                        <PromptEditor
                          value={updateItem.value?.[1] || ''}
                          onChange={handleUpdate}
                          showOpenModal={false}
                          variableLabels={variables}
                          minH={100}
                        />
                      </div>
                    );
                  }
                  if (valueType === WorkflowIOValueTypeEnum.number) {
                    return (
                      <NumberInput
                        value={Number(updateItem.value?.[1]) || 0}
                        onChange={(e) => {
                          handleUpdate(e?.toString() || '');
                        }}
                      />
                    );
                  }
                  if (valueType === WorkflowIOValueTypeEnum.boolean) {
                    return (
                      <Switch
                        defaultChecked={updateItem.value?.[1] === 'true'}
                        onChange={(e) => handleUpdate(String(e))}
                      />
                    );
                  }

                  return (
                    <div className="w-[300px]">
                      <PromptEditor
                        value={updateItem.value?.[1] || ''}
                        onChange={handleUpdate}
                        showOpenModal={false}
                        variableLabels={variables}
                        minH={100}
                      />
                    </div>
                  );
                })()}
              </div>
            </div>
          </div>

          {updateList.length > 1 && (
            <Button
              type="link"
              danger
              icon={<DeleteOutlined />}
              onMouseEnter={() => setHover(true)}
              onMouseLeave={() => setHover(false)}
              onClick={() => {
                setHover(false);
                onUpdateList(updateList.filter((_, i) => i !== index));
              }}
              className="peer w-[14px] cursor-pointer transition-opacity duration-200"
            />
          )}
        </div>
      );
    },
  );

  return (
    <NodeCard selected={selected} maxW="1000px" {...data}>
      <div className="px-4 pb-4">
        <div className="flex flex-col gap-2">
          {updateList.map((updateItem, index) => (
            <ValueRender key={index} updateItem={updateItem} index={index} />
          ))}
        </div>
        <div className="nodrag relative mt-2 flex cursor-default items-center justify-center">
          <Button
            type="text"
            icon={<PlusOutlined />}
            className="w-full"
            onClick={() => {
              onUpdateList([
                ...updateList,
                {
                  variable: ['', ''],
                  value: ['', ''],
                  renderType: FlowNodeInputTypeEnum.input,
                },
              ]);
            }}
          >
            添加变量
          </Button>
        </div>
      </div>
    </NodeCard>
  );
};
export default React.memo(NodeVariableUpdate);

const Reference = ({
  nodeId,
  variable,
  valueType,
  onSelect,
}: {
  nodeId: string;
  variable?: ReferenceValueProps;
  valueType?: WorkflowIOValueTypeEnum;
  onSelect: (e: ReferenceValueProps) => void;
}) => {
  const { referenceList, formatValue } = useReference({
    nodeId,
    valueType,
    value: variable,
  });

  return (
    <ReferSelector
      placeholder={t('select_reference_variable')}
      list={referenceList}
      value={formatValue}
      onSelect={onSelect}
    />
  );
};
